#include <iostream>
#include <leveldb/db.h>
#include <string>
#include <memory>
#include <leveldb/write_batch.h>
#include <exception>

#define DB_PATH "/tmp/leveldb"

void MustOk(leveldb::Status &&s)
{
	if (!s.ok())
		throw std::runtime_error{"leveldb not ok"};
	else
		return;
}

int main(int argc, char **argv)
{
	std::cout << DB_PATH << std::endl;
	leveldb::Options opts;
	opts.create_if_missing = true;

	leveldb::DB *dbptr = nullptr;

	leveldb::Status status = leveldb::DB::Open(opts, DB_PATH, &dbptr);
	if (status.ok())
	{
		std::cout << "leveldb open success" << std::endl;
	}
	else
	{
		std::cout << "failed to open db" << status.ToString() << std::endl;
	}

	std::unique_ptr<leveldb::DB> safedb{dbptr};

	leveldb::WriteOptions write_opt;
	write_opt.sync = false;
	leveldb::ReadOptions read_opt;
	read_opt.verify_checksums = false;

	MustOk(safedb->Put(write_opt, "apple", "apple"));
	MustOk(safedb->Put(write_opt, "pear", "pear"));
	MustOk(safedb->Put(write_opt, "jiba", "jiba"));
	MustOk(safedb->Put(write_opt, "code", "code"));
	MustOk(safedb->Put(write_opt, "women", "all slut"));

	// iterator how to use
	try
	{
		std::unique_ptr<leveldb::Iterator> it{
			{safedb->NewIterator(leveldb::ReadOptions())}};

		// it->Next();
		it->SeekToFirst();
		for (; it->Valid(); it->Next())
		{
			auto key = it->key().ToString();
			auto value = it->value().ToString();

			std::cout << "[ " << key << " : " << value << " ]" << std::endl;
		}

		for (it->SeekToLast(); it->Valid(); it->Next())
		{
			auto key = it->key().ToString();
			auto value = it->value().ToString();

			std::cout << "[ " << key << " : " << value << " ]" << std::endl;
		}

		for (it->Seek("pear"); it->Valid(); it->Next())
		{
			auto key = it->key().ToString();
			auto value = it->value().ToString();

			std::cout << "[ " << key << " : " << value << " ]" << std::endl;
		}

		for (it->Seek("a"); it->Valid(); it->Next())
		{
			auto key = it->key().ToString();
			auto value = it->value().ToString();

			std::cout << "[ " << key << " : " << value << " ]" << std::endl;
		}
	}
	catch (...)
	{
	}

	std::cout << status.ToString() << std::endl;

	return 0;
}
